home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Libraries / TransDisplay / Demos / C Demos / EventLog / EventLog.c next >
Text File  |  1994-02-21  |  28KB  |  1,259 lines

  1. /*
  2.  * Need to dispose of the Apple Event handlers?
  3.  *
  4.  * Need to check for new Std Get File routines.
  5.  */
  6.  
  7. /*
  8.  * EventLog - TransDisplay event-logging demonstration program
  9.  *
  10.  * The project should include EventLog.c (this file), TransDisplay.c
  11.  * (or a project made from TransDisplay.c), TransSkel.c (or a project
  12.  * made from TransSkel.c), and MacTraps.
  13.  *
  14.  * 08 Nov 86 Paul DuBois
  15.  * 28 Dec 86 Removed window zooming constants, since LightspeedC
  16.  * v. 2.01 now supports them directly.
  17.  * 01 Feb 89 Modified for TransSkel 2.0.  2-byte and 4-byte integer
  18.  * types are typedef'ed to Integer and Longint to ease porting.
  19.  * 05 Jun 93
  20.  * - Use SkelDlogFilter() in DoAbout() so that update events for document
  21.  * windows are seen and logged.
  22.  * - Conversion for THINK C 6.0.  Also conversion for TransSkel 3.00.
  23.  * 16 Oct 93
  24.  * - Added some support for OS and high-level events.  Open Application,
  25.  * Quit Application, Open Documents, and Print Documents are reported
  26.  * (i.e., the four required core Apple Events).
  27.  * Apple Event logging is a little different than other events, since not
  28.  * all event information is in the EventRecord.  They're just reported through
  29.  * the regular Apple Event routing mechanism.
  30.  * 19 Oct 93
  31.  * - Add Launch item to File menu to prepare for allowing app launches so
  32.  * can catch app-died events.  Add handler for Application Died Apple Event.
  33.  * 06 Nov 93
  34.  * - ReportKey() now reports the key code in addition to the character, in
  35.  * keeping with a change made some time ago to TransSkel's key handler that
  36.  * passes both.
  37.  * 04 Jan 94
  38.  * - Undid Integer/LongInt type stuff back to short/long.
  39.  * 18 Jan 94
  40.  * - Updated for TransDisplay 3.04.
  41.  * 21 Feb 94
  42.  * - Updated for TransSkel 3.11, TransDisplay 3.05.
  43.  */
  44.  
  45.  
  46. #include    <GestaltEqu.h>
  47. #include    <AppleEvents.h>
  48.  
  49.  
  50. #include    "TransSkel.h"
  51.  
  52. #include    "TransDisplay.h"
  53.  
  54.  
  55. #define PtToLong(pt)    (* (long *) &pt)
  56.  
  57. #define    maxButton    19
  58.  
  59.  
  60. #define    helpTextRes        1000    /* help text resource number */
  61. #define    aboutAlrtRes    1000    /* About... alert resource number */
  62.  
  63.  
  64. typedef enum                    /* Menu resource numbers */
  65. {
  66.     fileMenuRes = 1000,
  67.     editMenuRes,
  68.     logMenuRes
  69. };
  70.  
  71.  
  72. typedef enum                    /* Window resource numbers */
  73. {
  74.     logWindRes = 1000,
  75.     helpWindRes,
  76.     selectWindRes
  77. };
  78.  
  79.  
  80. typedef enum            /* File menu item numbers */
  81. {
  82.     showLog = 1,    /* make windows visible/bring to front */
  83.     showHelp,
  84.     showSelect,
  85.     /* --- */
  86.     launchApp = 5,
  87.     /* --- */
  88.     quit = 7
  89. };
  90.  
  91.  
  92. typedef enum                /* Edit menu item numbers */
  93. {
  94.     undo = 1,
  95.     /* --- */
  96.     cut = 3,
  97.     copy,
  98.     paste,
  99.     clear
  100. };
  101.  
  102.  
  103. typedef enum                /* Log menu item numbers */
  104. {
  105.     logEvents = 1,        /* whether events are logged */
  106.     excludeLWind,
  107.     /* --- */
  108.     flushLog = 4,        /* flush log output */
  109.     /* --- */
  110.     wrapStyle = 6,        /* word wrap or not */
  111.     /* --- */
  112.     leftJust = 8,        /* justification */
  113.     centerJust,
  114.     rightJust,
  115.     /* --- */
  116.     small = 12,            /* text size */
  117.     medium,
  118.     large,
  119.     /* --- */
  120.     top = 16,            /* scroll home */
  121.     bottom                /* scroll to bottom */
  122. };
  123.  
  124.  
  125. typedef struct CtrlInfo
  126. {
  127.     Point            loc;        /* upper left of control */
  128.     Str255            title;        /* control title */
  129.     Boolean            *flagAddr;    /* associated boolean */
  130.     ControlHandle    ctrl;        /* associated control */
  131.     struct CtrlInfo    *subInfo;    /* subsidiary control */
  132.  
  133. } CtrlInfo;
  134.  
  135.  
  136. WindowPtr    selectWind;            /* event selection window */
  137. WindowPtr    helpWind;            /* help text window */
  138. WindowPtr    logWind;            /* log output window */
  139. MenuHandle    fileMenu;
  140. MenuHandle    editMenu;
  141. MenuHandle    logMenu;
  142. Boolean        reportEvents;        /* report events or not */
  143. Boolean        excludeLog;            /* exclude log window events or not */
  144. short        logFont;
  145. short        logSize;
  146. short        logWrap;
  147. short        logJust;
  148.  
  149.  
  150. Boolean                            /* event type selection flags */
  151.         rMouseDown = true,
  152.             rMouseMods = false,
  153.             rMouseWind = true,
  154.             rMouseLoc = false,
  155.             rMousePart = true,
  156.             rMouseSys = false,
  157.         rMouseUp = false,
  158.         rKeyDown = true,
  159.             rKDMods = false,
  160.         rAutoKey = true,
  161.             rAKMods = false,
  162.         rUpdate = true,
  163.         rActivate = true,
  164.         rDisk = true,
  165.         rOS = true,
  166.             rOSSuspendResume = true,
  167.             rOSMouseMoved = true,
  168.             rOSChildDied = true,
  169.         rHighLevel = true;
  170.  
  171.  
  172. /*
  173.     Control information.  The last field is used to tell which controls
  174.     are "owned" by another.  When the owner is unchecked, all the owned
  175.     controls go dim.
  176. */
  177.  
  178. CtrlInfo    ctrlInfo [maxButton] =
  179. {
  180.     { { 5, 10}, "\pMouse Down", &rMouseDown, nil, nil },
  181.     { { 25, 30}, "\pModifiers", &rMouseMods, nil, &ctrlInfo[0] },
  182.     { { 45, 30}, "\pWindow", &rMouseWind, nil, &ctrlInfo[0] },
  183.     { { 65, 30}, "\pLocation", &rMouseLoc, nil, &ctrlInfo[0] },
  184.     { { 85, 30}, "\pPart Code", &rMousePart, nil, &ctrlInfo[0] },
  185.     { { 105, 30}, "\pSystem Clicks", &rMouseSys, nil, &ctrlInfo[0] },
  186.     { { 125, 10}, "\pMouse Up", &rMouseUp, nil, nil },
  187.     { { 5, 150}, "\pKey Down", &rKeyDown, nil, nil },
  188.     { { 25, 170}, "\pModifiers", &rKDMods, nil, &ctrlInfo[7] },
  189.     { { 45, 150}, "\pAutoKey", &rAutoKey, nil, nil },
  190.     { { 65, 170}, "\pModifiers", &rAKMods, nil, &ctrlInfo[9] },
  191.     { { 85, 150}, "\pUpdate", &rUpdate, nil, nil },
  192.     { { 105, 150}, "\pActivate", &rActivate, nil, nil },
  193.     { { 125, 150}, "\pDisk", &rDisk, nil, nil },
  194.     { { 5, 265}, "\pOS Event", &rOS, nil, nil },
  195.     { { 25, 285}, "\pSuspend", &rOSSuspendResume, nil, &ctrlInfo[14] },
  196.     { { 45, 285}, "\pMouse Moved", &rOSMouseMoved, nil, &ctrlInfo[14] },
  197.     { { 65, 285}, "\pChild Died", &rOSChildDied, nil, &ctrlInfo[14] },
  198.     { { 85, 265}, "\pHigh Level", &rHighLevel, nil, nil }
  199. };
  200.  
  201. /*    Window that was in front last time checked    */
  202.  
  203. WindowPtr    lastFront = nil;
  204.  
  205. static Boolean    inForeground = true;
  206.  
  207.  
  208. /*
  209.     Print information about a window.  If it's a window with a title,
  210.     print the title.  Print whether it's a desk accessory window.
  211. */
  212.  
  213. static void
  214. WindowInfo (theWind)
  215. WindowPeek    theWind;
  216. {
  217. Str255    title;
  218.  
  219.     GetWTitle ((WindowPtr) theWind, title);
  220.     if (title[0] != 0)            /* window has title */
  221.     {
  222.         DisplayChar (' ');
  223.         DisplayString (title);
  224.     }
  225.  
  226.     if (theWind->windowKind < 0)
  227.         DisplayString ("\p (DA)");
  228. }
  229.  
  230.  
  231. static void
  232. Modifiers (mods)
  233. short    mods;
  234. {
  235.     DisplayString ("\p modifiers 0x");
  236.     DisplayHexShort (mods);
  237. }
  238.  
  239.  
  240. static void
  241. MouseLoc (thePt, thePort)
  242. Point    thePt;
  243. GrafPtr    thePort;
  244. {
  245. GrafPtr    savePort;
  246.  
  247.     GetPort (&savePort);
  248.     SetPort (thePort);
  249.     GlobalToLocal (&thePt);
  250.     SetPort (savePort);
  251.     if (rMouseLoc)
  252.     {
  253.         DisplayString ("\p loc (");
  254.         DisplayShort (thePt.h);
  255.         DisplayString ("\p, ");
  256.         DisplayShort (thePt.v);
  257.         DisplayChar (')');
  258.     }
  259. }
  260.  
  261.  
  262. /*
  263.     Mouse click.  Get the window that the click occurred in, and the
  264.     part of the window.
  265.  
  266.     Make sure to get all the part codes!  (incl. zoom box stuff)
  267. */
  268.  
  269. static void
  270. ReportMouse (EventRecord *theEvent)
  271. {
  272. Point    evtPt;
  273. short    evtPart;
  274. GrafPtr    evtPort;
  275.  
  276.     evtPt = theEvent->where;
  277.     evtPart = FindWindow (evtPt, &evtPort);
  278.     if (excludeLog && evtPort == logWind)
  279.         return;
  280.     DisplayString ("\pMouse click");
  281.  
  282.     switch (evtPart)
  283.     {
  284.     default:
  285.         if (rMousePart)
  286.         {
  287.             DisplayString ("\p in unknown part code ");
  288.             DisplayShort (evtPart);
  289.         }
  290.         break;
  291.  
  292.     /*
  293.      * Click in a desk accessory window.
  294.      */
  295.     case inSysWindow:
  296.         if (rMouseSys)
  297.         {
  298.             if (rMousePart)
  299.                 DisplayString ("\p in system window:");
  300.             if (rMouseWind)
  301.                 WindowInfo ((WindowPeek) evtPort);
  302.             MouseLoc (evtPt, evtPort);
  303.         }
  304.         break;
  305.  
  306.     /*
  307.      * Click in desk top.
  308.      */
  309.     case inDesk:
  310.         if (rMousePart)
  311.             DisplayString ("\p in desktop");
  312.         break;
  313.  
  314.     /*
  315.      * Click in menu bar.
  316.      */
  317.     case inMenuBar:
  318.         if (rMousePart)
  319.             DisplayString ("\p in menu bar");
  320.         break;
  321.  
  322.     /*
  323.      * Click in grow box.
  324.      */
  325.     case inGrow:
  326.         if (rMousePart)
  327.             DisplayString ("\p in grow region:");
  328.         if (rMouseWind)
  329.             WindowInfo ((WindowPeek) evtPort);
  330.         MouseLoc (evtPt, evtPort);
  331.         break;
  332.  
  333.     /*
  334.      * Click in title bar.
  335.      */
  336.     case inDrag:
  337.         if (rMousePart)
  338.             DisplayString ("\p in drag region:");
  339.         if (rMouseWind)
  340.             WindowInfo ((WindowPeek) evtPort);
  341.         break;
  342.  
  343.     /*
  344.      * Click in close box.
  345.      */
  346.     case inGoAway:
  347.         if (rMousePart)
  348.             DisplayString ("\p in close box:");
  349.         if (rMouseWind)
  350.             WindowInfo ((WindowPeek) evtPort);
  351.         break;
  352.  
  353.     /*
  354.      * Click in zoom-in box.
  355.      */
  356.     case inZoomIn:
  357.         if (rMousePart)
  358.             DisplayString ("\p in zoom-in box:");
  359.         if (rMouseWind)
  360.             WindowInfo ((WindowPeek) evtPort);
  361.         break;
  362.  
  363.     /*
  364.      * Click in zoom-out box.
  365.      */
  366.     case inZoomOut:
  367.         if (rMousePart)
  368.             DisplayString ("\p in zoom-out box:");
  369.         if (rMouseWind)
  370.             WindowInfo ((WindowPeek) evtPort);
  371.         break;
  372.  
  373.     /*
  374.      * Click in content region.
  375.      *
  376.      * (some day - check if in control, and if so, print control information)
  377.      */
  378.     case inContent:
  379.         if (rMousePart)
  380.             DisplayString ("\p in content region:");
  381.         if (rMouseWind)
  382.             WindowInfo ((WindowPeek) evtPort);
  383.         MouseLoc (evtPt, evtPort);
  384.         break;
  385.     }
  386.  
  387.     if (rMouseMods)
  388.         Modifiers (theEvent->modifiers);
  389.     DisplayLn ();
  390. }
  391.  
  392.  
  393. /*
  394.  * The high bit of the key code is set if the event is a key up event.
  395.  * Actually, this will never be reported since the default event mask
  396.  * excludes key ups.  I'm not sure the system reports them anymore anyway,
  397.  * even if you change the event mask...
  398.  */
  399.  
  400. static void
  401. ReportKey (short what, char c, unsigned char code, short mods, Boolean modFlag)
  402. {
  403.     if (what == keyDown)
  404.         DisplayString ("\pKey down: char '");
  405.     else
  406.         DisplayString ("\pAutokey: char '");
  407.     DisplayChar (c);
  408.     DisplayString ("\p', code 0x");
  409.     DisplayHexShort ((short) code);
  410.     if (modFlag)
  411.     {
  412.         DisplayString ("\p,");
  413.         Modifiers (mods);
  414.     }
  415.     DisplayLn ();
  416. }
  417.  
  418.  
  419. static void
  420. ReportActivate (WindowPtr theWind, short mods)
  421. {
  422.     if ((mods & activeFlag) != 0)
  423.         DisplayString ("\pActivate:");
  424.     else
  425.         DisplayString ("\pDeactivate:");
  426.     WindowInfo ((WindowPeek) theWind);
  427.     DisplayLn ();
  428. }
  429.  
  430.  
  431. static  void
  432. ReportUpdate (WindowPtr theWind)
  433. {
  434.     DisplayString ("\pUpdate:");
  435.     WindowInfo ((WindowPeek) (WindowPeek) theWind);
  436.     DisplayLn ();
  437. }
  438.  
  439.  
  440. /*
  441.  * General event logger.  This is essentially a modified copy of
  442.  * SkelRouteEvent().  Null events are not recorded because they occur
  443.  * too frequently.
  444.  */
  445.  
  446. static pascal Boolean
  447. LogEvent (EventRecord *theEvent)
  448. {
  449. Point            evtPt;
  450. long            evtMsge;
  451. GrafPtr            tmpPort;
  452. short            evtPart;
  453. char            evtChar;
  454. unsigned char    evtCode;
  455. short            evtMods;
  456. Rect            r;
  457. short            osMsge;
  458. Boolean            osSuspend;
  459. Boolean            osClipCvt;
  460.  
  461. /*
  462. if (theEvent->what != 0)
  463. {
  464.     DisplayString ("\pEvent number: ");
  465.     DisplayLong ((long) theEvent->what);
  466.     DisplayLn ();
  467. }
  468. */
  469.     if (reportEvents == false)
  470.         return (false);            /* don't do anything */
  471.     evtPt = theEvent->where;
  472.     evtMsge = theEvent->message;
  473.     evtMods = theEvent->modifiers;
  474.  
  475.     switch (theEvent->what)
  476.     {
  477.  
  478. /*
  479.     Mouse click.
  480. */
  481.         case mouseDown:
  482.             if (rMouseDown)
  483.                 ReportMouse (theEvent);
  484.             break;
  485.  
  486.         case mouseUp:
  487.             if (rMouseUp)
  488.                 DisplayString ("\pMouse up\r");
  489.             break;
  490.  
  491. /*
  492.     Key event.
  493. */
  494.         case keyDown:
  495.             if (excludeLog && FrontWindow () == logWind)
  496.                 break;
  497.             if (rKeyDown)
  498.             {
  499.                 evtChar = evtMsge & charCodeMask;
  500.                 evtCode = (evtMsge & keyCodeMask) >> 8;
  501.                 ReportKey (keyDown, evtChar, evtCode, evtMods, rKDMods);
  502.             }
  503.             break;
  504.  
  505.         case autoKey:
  506.             if (excludeLog && FrontWindow () == logWind)
  507.                 break;
  508.             if (rKeyDown)
  509.             {
  510.                 evtChar = evtMsge & charCodeMask;
  511.                 evtCode = (evtMsge & keyCodeMask) >> 8;
  512.                 ReportKey (autoKey, evtChar, evtCode, evtMods, rAKMods);
  513.             }
  514.             break;
  515.  
  516. /*
  517.     Update a window.  If it's an update for the log window, invalidate
  518.     it, because the message is written and will cause a scroll BEFORE
  519.     the window actually gets updated.  This means that part of what
  520.     needs redrawing will be scrolled out of the update region and won't
  521.     be redrawn properly.  Invalidating the entire port is wasteful but
  522.     makes sure the whole window can be drawn properly.
  523. */
  524.         case updateEvt:
  525.             if ((WindowPtr) evtMsge == logWind)
  526.             {
  527.                 GetPort (&tmpPort);
  528.                 SetPort (logWind);
  529.                 InvalRect (&logWind->portRect);
  530.                 SetPort (tmpPort);
  531.             }
  532.             if (excludeLog && (WindowPtr) evtMsge == logWind)
  533.                 break;
  534.             if (rUpdate)
  535.                 ReportUpdate ((WindowPtr) evtMsge);
  536.             break;
  537.  
  538. /*
  539.     Activate or deactivate a window.
  540. */
  541.         case activateEvt:
  542.             if (excludeLog && (WindowPtr) evtMsge == logWind)
  543.                 break;
  544.             if (rActivate)
  545.                 ReportActivate ((WindowPtr) evtMsge, theEvent->modifiers);
  546.             break;
  547.  
  548. /*
  549.     handle inserts of uninitialized disks
  550. */
  551.         case diskEvt:
  552.             if (rDisk)
  553.             {
  554.                 DisplayString ("\pDisk insertion");
  555.                 if (HiWord (evtMsge) != noErr)
  556.                 {
  557.                     DisplayString ("\p (needs initializing)");
  558.                 }
  559.                 DisplayLn ();
  560.             }
  561.             break;
  562.  
  563.     
  564.         case osEvt:                /* aka app4Evt aka MultiFinder event */
  565.             if (!rOS)
  566.                 break;
  567.             DisplayString ("\pOS event:");
  568.             /* rip the message field into constituent parts */
  569.             osMsge = ((evtMsge >> 24) & 0xff);            /* high byte */
  570.             osSuspend = (Boolean) ((evtMsge & 1) == 0);    /* suspend application */
  571.             osClipCvt = (Boolean) ((evtMsge & 2) != 0);    /* convert clipboard ? */
  572.  
  573.             switch (osMsge)
  574.             {
  575.             case    1:                /* suspend or resume event */
  576.                 inForeground = !osSuspend;
  577.                 if (osSuspend)            /* always convert on suspend */
  578.                     osClipCvt = true;
  579.                 if (inForeground)
  580.                     DisplayString ("\p resume");
  581.                 else
  582.                     DisplayString ("\p suspend");
  583.                 if (osClipCvt)
  584.                     DisplayString ("\p (convert clipboard)");
  585.                 else
  586.                     DisplayString ("\p (do not convert clipboard)");
  587.                 break;
  588.  
  589.             case 0xfa:                /* mouse-moved event */
  590.                 /*
  591.                  * Not likely to be executed since EventLog doesn't 
  592.                  * do anything about changing cursor
  593.                  */
  594.                 DisplayString ("\pmouse moved");
  595.                 break;
  596.  
  597.             case 0xfd:                /* child-died event */
  598.                 /* SADE-only event */
  599.                 /* child pid is byte 2 (evtMsge >> 16) & 0xffL) */
  600.                 DisplayString ("\p sade (pid ");
  601.                 DisplayShort ((evtMsge >> 16) & 0xff);
  602.                 DisplayString ("\p)");
  603.                 break;
  604.  
  605.             default:                /* other event */
  606.                 DisplayString ("\p unknown type");
  607.                 break;
  608.             }
  609.             DisplayLn ();
  610.             break;
  611.  
  612.         case kHighLevelEvent:
  613.             /* Handled by LogAppleEvent() */
  614.             break;
  615.  
  616.     }
  617.     return (false);        /* never tell TransSkel the event was handled */
  618. }
  619.  
  620.  
  621. static pascal void
  622. LogAppleEvent (EventRecord *theEvent)
  623. {
  624.     if (!rHighLevel)
  625.         return;
  626.  
  627.     DisplayString ("\pHigh level event '");
  628.     DisplayOSType ((OSType) theEvent->message);
  629.     DisplayString ("\p' '");
  630.     DisplayOSType ((OSType) PtToLong (theEvent->where));
  631.     DisplayString ("\p'");
  632.     DisplayLn ();
  633.     AEProcessAppleEvent (theEvent);
  634. }
  635.  
  636.  
  637. /*
  638.  * Handler for Open Application or Quit Application Apple Events.
  639.  * Reference constant is 0 for Open, 1 for Quit.
  640.  * Note that it must be a pascal function!
  641.  */
  642.  
  643. static pascal OSErr
  644. AEOpenOrQuitApp (AppleEvent *theAEvt, AppleEvent *replyEvt, long refCon)
  645. {
  646. long    items;
  647.  
  648.     if (refCon == 0L)
  649.         DisplayString ("\pOpen Application Apple event");
  650.     else
  651.         DisplayString ("\pQuit Application Apple event");
  652.     DisplayLn ();
  653.     return (noErr);
  654. }
  655.  
  656.  
  657. /*
  658.  * Handler for Open Document or Print Document Apple Events.
  659.  * Reference constant is 0 for Open, 1 for Print.
  660.  * Note that it must be a pascal function!
  661.  */
  662.  
  663. static pascal OSErr
  664. AEOpenOrPrintDoc (AppleEvent *theAEvt, AppleEvent *replyEvt, long refCon)
  665. {
  666. long        items, index;
  667. FSSpec        myFSS;
  668. AEDescList    docList;
  669. AEKeyword    keywd;
  670. DescType    returnedType;
  671. long        actualSize;
  672. OSErr        myErr;
  673.  
  674.     if (refCon == 0L)
  675.         DisplayString ("\pOpen Document Apple event");
  676.     else
  677.         DisplayString ("\pPrint Document Apple event");
  678.     DisplayLn ();
  679.     myErr = AEGetParamDesc (theAEvt, keyDirectObject, typeAEList, &docList);
  680.     if (myErr != noErr)
  681.         return (myErr);
  682.  
  683.     /* should check for missing required parameters here */
  684.  
  685.     DisplayString ("\pNumber of items: ");
  686.     if ((myErr = AECountItems (&docList, &items)) != noErr)
  687.     {
  688.         DisplayString ("\p(couldn't tell - error occurred)");
  689.         DisplayLn ();
  690.         return (myErr);
  691.     }
  692.     DisplayLong (items);
  693.     DisplayLn ();
  694.     for (index = 1; index <= items; index++)
  695.     {
  696.         myErr = AEGetNthPtr (&docList, index, typeFSS, &keywd, &returnedType,
  697.                         &myFSS, sizeof (myFSS), &actualSize);
  698.         if (myErr != noErr)
  699.             return (myErr);
  700.         DisplayString ("\pItem ");
  701.         DisplayLong (index);
  702.         DisplayString ("\p: name = ");
  703.         DisplayString ((StringPtr) myFSS.name);
  704.         DisplayString ("\p, vRefNum = ");
  705.         DisplayShort (myFSS.vRefNum);
  706.         DisplayString ("\p, parID = ");
  707.         DisplayLong (myFSS.parID);
  708.         DisplayLn ();
  709.     }
  710.     myErr = AEDisposeDesc (&docList);
  711.     return (myErr);
  712. }
  713.  
  714.  
  715. /*
  716.  * Handler for Application Died Apple Event.
  717.  * This will be called if/when any application launched by selecting
  718.  * File/Launch exits.
  719.  * Note that it must be a pascal function!
  720.  */
  721.  
  722. static pascal OSErr
  723. AEAppDied (AppleEvent *theAEvt, AppleEvent *replyEvt, long refCon)
  724. {
  725. OSErr        myErr;
  726. OSErr        appDiedErr;
  727. DescType    returnedType;
  728. long        actualSize;
  729. ProcessSerialNumber    psn;
  730.  
  731.     DisplayString ("\pApplication Died Apple event");
  732.     DisplayLn ();
  733.  
  734.     DisplayString ("\pProcess serial number: ");
  735.     myErr = AEGetParamPtr (theAEvt, keyProcessSerialNumber, typeProcessSerialNumber,
  736.                                 &returnedType, &psn, sizeof (psn), &actualSize);
  737.     if (myErr == noErr)
  738.     {
  739.         DisplayLong (psn.highLongOfPSN);
  740.         DisplayChar ('/');
  741.         DisplayLong (psn.lowLongOfPSN);
  742.     }
  743.     else
  744.         DisplayString ("\pcould not get psn.");
  745.     DisplayLn ();
  746.  
  747.     DisplayString ("\pReturn status: ");
  748.     myErr = AEGetParamPtr (theAEvt, keyErrorNumber, typeLongInteger,
  749.                         &returnedType, &appDiedErr, sizeof (appDiedErr), &actualSize);
  750.     if (myErr == noErr)
  751.         DisplayLong (appDiedErr);
  752.     else
  753.         DisplayString ("\pcould not get return status.");
  754.     DisplayLn ();
  755.  
  756.     /* should check for missing required parameters here */
  757.  
  758.     return (noErr);
  759. }
  760.  
  761.  
  762. /* ------------------------------------------------------------ */
  763. /*            Event Selection Window Handler Routines                */
  764. /* ------------------------------------------------------------ */
  765.  
  766.  
  767. /*
  768.     Activate event procedure for both display windows and the checkbox
  769.     window.
  770. */
  771.  
  772. static pascal void
  773. Activate (Boolean active)
  774. {
  775. }
  776.  
  777. /*
  778.     Update window.  This is easy, just draw the controls.
  779. */
  780.  
  781. static pascal void
  782. Update (Boolean resized)
  783. {
  784.     DrawControls (selectWind);
  785. }
  786.  
  787.  
  788. /*
  789.     Handle hits in check boxes of selection window:
  790.     Toggle check box, sync the associated flag, and enable or disable
  791.     any subsidiary check boxes accordingly.  (Subsidiaries have
  792.     information in the control structure that points back to the owner
  793.     check box.)
  794.  
  795. */
  796.  
  797. static pascal void
  798. Mouse (Point thePt, long t, short mods)
  799. {
  800. ControlHandle    ctl;
  801. CtrlInfo        *ci;
  802. Boolean            val;
  803. short            i;
  804.  
  805.     if (FindControl (thePt, selectWind, &ctl))
  806.     {
  807.         if (TrackControl (ctl, thePt, nil))
  808.         {
  809.             ci = (CtrlInfo *) GetCRefCon (ctl);
  810.             val = !GetCtlValue (ctl);
  811.             *(ci->flagAddr) = val;
  812.             SetCtlValue (ctl, val);
  813.         
  814.             /* enable/disable any subsidiaries */
  815.         
  816.             for (i = 0; i < maxButton; ++i)
  817.             {
  818.                 if (ctrlInfo[i].subInfo->ctrl == ci->ctrl)
  819.                     HiliteControl (ctrlInfo[i].ctrl, val ? 0 : 255);
  820.             }
  821.         }
  822.     }
  823. }
  824.  
  825.  
  826. /* ------------------------------------------------------------ */
  827. /*            Menu Hook and Menu Handler Routines                    */
  828. /* ------------------------------------------------------------ */
  829.  
  830.  
  831. /*
  832.  * Menu hook procedure.  Check front window, reset edit menu depending on
  833.  * whether front window is an application window or a DA window (items are
  834.  * only active for a DA window).
  835.  */
  836.  
  837. static pascal void
  838. MyMenuHook (void)
  839. {
  840. WindowPtr    w;
  841. short        theKind;
  842.  
  843.     DisableItem (editMenu, undo);
  844.     DisableItem (editMenu, cut);
  845.     DisableItem (editMenu, copy);
  846.     DisableItem (editMenu, paste);
  847.     DisableItem (editMenu, clear);
  848.  
  849.     if ((w = FrontWindow ()) != (WindowPtr) nil)
  850.     {
  851.         if (((WindowPeek) w)->windowKind < 0)    /* DA in front */
  852.         {
  853.             EnableItem (editMenu, undo);
  854.             EnableItem (editMenu, cut);
  855.             EnableItem (editMenu, copy);
  856.             EnableItem (editMenu, paste);
  857.             EnableItem (editMenu, clear);
  858.         }
  859.     }
  860. }
  861.  
  862.  
  863. /*
  864.  * Handle selection of About... item from Apple menu.
  865.  * Use of SkelDlogFilter() is important here because it makes
  866.  * sure the event hook is called even while the alert is up.
  867.  */
  868.  
  869. static pascal void
  870. DoAbout (short item)
  871. {
  872.     (void) SkelAlert (aboutAlrtRes, SkelDlogFilter (nil, true),
  873.                                                 skelPositionOnParentDevice);
  874.     SkelRmveDlogFilter ();
  875. }
  876.  
  877.  
  878. /*
  879.  * File menu handler.
  880.  *
  881.  * The launchApp item will be disable and cannot be selected unless
  882.  * the system supports the new standard file dialogs and application
  883.  * launching.
  884.  */
  885.  
  886. static pascal void
  887. DoFileMenu (short item)
  888. {
  889. LaunchParamBlockRec    lParams;
  890. StandardFileReply    appSFR;
  891. SFTypeList            types;
  892. OSErr                myErr;
  893.  
  894.     switch (item)
  895.     {
  896.     case showHelp:
  897.         SelectWindow (helpWind);
  898.         ShowWindow (helpWind);
  899.         break;
  900.     
  901.     case showSelect:
  902.         SelectWindow (selectWind);
  903.         ShowWindow (selectWind);
  904.         break;
  905.     
  906.     case showLog:
  907.         SelectWindow (logWind);
  908.         ShowWindow (logWind);
  909.         break;
  910.     
  911.     case launchApp:
  912.         types[0] = 'APPL';    /* to launch any application */
  913.         StandardGetFile (nil, 1, types, &appSFR);        
  914.         if (appSFR.sfGood)
  915.         { 
  916.             
  917.             lParams.launchBlockID = extendedBlock;
  918.             lParams.launchEPBLength = extendedBlockLen;
  919.             lParams.launchFileFlags = 0;
  920.             lParams.launchControlFlags = launchContinue + launchNoFileFlags;
  921.             lParams.launchAppSpec = &(appSFR.sfFile);
  922.             lParams.launchAppParameters = nil;
  923.             
  924.             if ((myErr = LaunchApplication (&lParams)) != noErr)
  925.             {
  926.                 DisplayString ("\pLaunch failed, error = \r");
  927.                 DisplayLong (myErr);
  928.                 DisplayLn ();
  929.             }
  930.         }
  931.         break;
  932.     
  933.     case quit:
  934.         SkelStopEventLoop ();
  935.         break;
  936.     }
  937. }
  938.  
  939. /*
  940.     Put the right check marks in the Log menu
  941. */
  942.  
  943. static pascal void
  944. SetLogMenu ()
  945. {
  946.     CheckItem (logMenu, logEvents, reportEvents);
  947.     CheckItem (logMenu, excludeLWind, excludeLog);
  948.     CheckItem (logMenu, wrapStyle, logWrap >= 0);
  949.     CheckItem (logMenu, leftJust, logJust == teJustLeft);
  950.     CheckItem (logMenu, centerJust, logJust == teJustCenter);
  951.     CheckItem (logMenu, rightJust, logJust == teJustRight);
  952.     CheckItem (logMenu, small, logSize == 9);
  953.     CheckItem (logMenu, medium, logSize == 12);
  954.     CheckItem (logMenu, large, logSize == 24);
  955. }
  956.  
  957.  
  958. /*
  959.     Set display style of log window
  960. */
  961.  
  962. static void
  963. SetStyle ()
  964. {
  965.     SetDWindowStyle (logWind, logFont, logSize, logWrap, logJust);
  966.     SetLogMenu ();
  967. }
  968.  
  969.  
  970. /*
  971.     Log menu handler
  972. */
  973.  
  974. static pascal void
  975. DoLogMenu (short item)
  976. {
  977.     switch (item)
  978.     {
  979.     case logEvents:
  980.         reportEvents = !reportEvents;
  981.         SetLogMenu ();
  982.         break;
  983.  
  984.     case excludeLWind:
  985.         excludeLog = !excludeLog;
  986.         SetLogMenu ();
  987.         break;
  988.  
  989.     case flushLog:
  990.         FlushDWindow (logWind, 32767L);
  991.         break;
  992.     
  993.     case wrapStyle:
  994.         logWrap = (logWrap >= 0 ? -1 : 0);
  995.         SetStyle ();
  996.         break;
  997.  
  998.     case leftJust:
  999.         logJust = teJustLeft;
  1000.         SetStyle ();
  1001.         break;
  1002.  
  1003.     case centerJust:
  1004.         logJust = teJustCenter;
  1005.         SetStyle ();
  1006.         break;
  1007.  
  1008.     case rightJust:
  1009.         logJust = teJustRight;
  1010.         SetStyle ();
  1011.         break;
  1012.  
  1013.     case small:
  1014.         logFont = monaco;
  1015.         logSize = 9;
  1016.         SetStyle ();
  1017.         break;
  1018.  
  1019.     case medium:
  1020.         logFont = systemFont;
  1021.         logSize = 12;
  1022.         SetStyle ();
  1023.         break;
  1024.  
  1025.     case large:
  1026.         logFont = geneva;
  1027.         logSize = 24;
  1028.         SetStyle ();
  1029.         break;
  1030.  
  1031.     case top:
  1032.         SetDWindowPos (logWind, 0);
  1033.         break;
  1034.  
  1035.     case bottom:
  1036.         SetDWindowPos (logWind, 32767);
  1037.         break;
  1038.     }
  1039. }
  1040.  
  1041.  
  1042. /*
  1043.     Dispose of event selection window (and controls)
  1044. */
  1045.  
  1046. static pascal void
  1047. WClobber (void)
  1048. {
  1049.     DisposeWindow (selectWind);
  1050. }
  1051.  
  1052.  
  1053.  
  1054. /*
  1055.     Create controls
  1056. */
  1057.  
  1058. static void
  1059. MakeControls (theWind)
  1060. WindowPtr    theWind;
  1061. {
  1062. short        i;
  1063. CtrlInfo    *ci;
  1064. Rect        r;
  1065.  
  1066.     for (i = 0; i < maxButton; ++i)
  1067.     {
  1068.         ci = &ctrlInfo[i];
  1069.         SetRect (&r, ci->loc.h, ci->loc.v,
  1070.                     ci->loc.h + StringWidth (ci->title) + 30,
  1071.                     ci->loc.v + 20);
  1072.         ci->ctrl = NewControl (theWind, &r, ci->title, true,
  1073.                             *(ci->flagAddr), 0, 1,
  1074.                             checkBoxProc, (long) ci);
  1075.     }
  1076.     ValidRect (&theWind->portRect);
  1077.  
  1078.     /*
  1079.      * Disable high-level button if high-level events aren't present.
  1080.      * (Assumes high-level button is last)
  1081.      */
  1082.     if (!rHighLevel)
  1083.         HiliteControl (ctrlInfo[maxButton-1].ctrl, 255);
  1084. }
  1085.  
  1086. /*
  1087.  * Handle suspend/resume events.  This function is called only if the
  1088.  * "Suspend & Resume Events" bit is set in the 'SIZE' -1 resource.  It
  1089.  * assumes that the "MultiFinder-Aware" bit is also set, which means that
  1090.  * the application handles activate/deactivate of frontmost window on
  1091.  * suspend/resume:
  1092.  * - On a suspend, deactivate the frontmost window.
  1093.  * - On a resume, don't just blindly activate the frontmost window.  The
  1094.  * user may have brought the application to the front by clicking in some
  1095.  * other window.  That click will bring the other window to the front when
  1096.  * it's processed, so the frontmost window will just immediately be deactivated
  1097.  * after being activated.  This is ugly.  Instead, check whether or not a
  1098.  * mouse click is in the event queue.  If it is, and it's a click in the
  1099.  * frontmost window, activate that window.  Otherwise, don't activate anything.
  1100.  * When the click is processed, the right window will be activated.
  1101.  */
  1102.  
  1103. static pascal void
  1104. DoSuspendResume (Boolean inForeground)
  1105. {
  1106. EventRecord    event;
  1107. WindowPtr    w = FrontWindow ();
  1108. GrafPtr        eventPort;
  1109. Boolean        doActivate;
  1110.  
  1111.     if (!inForeground)        /* suspend is imminent */
  1112.     {
  1113.         SkelActivate (w, false);
  1114.     }
  1115.     else                    /* resume is imminent */
  1116.     {
  1117.         doActivate = true;
  1118.         if (EventAvail (mDownMask, &event))
  1119.         {
  1120.             (void) FindWindow (event.where, &eventPort);
  1121.             if (eventPort != w)
  1122.                 doActivate = false;
  1123.         }
  1124.         if (doActivate)
  1125.             SkelActivate (w, true);
  1126.     }
  1127. }
  1128.  
  1129.  
  1130. int
  1131. main ()
  1132. {
  1133. Handle    h;
  1134. long    result;
  1135.  
  1136.     SkelInit ((SkelInitParamsPtr) nil);
  1137.  
  1138.     /*
  1139.      * If Apple Events are available, install handlers for the core required
  1140.      * events, and the Application Died event.
  1141.      */
  1142.  
  1143.     if (!SkelQuery (skelQHasAppleEvents))
  1144.         rHighLevel = false;
  1145.     else
  1146.     {
  1147.         SkelSetAEHandler (LogAppleEvent);
  1148.         if (AEInstallEventHandler (kCoreEventClass, kAEOpenApplication,
  1149.                                         AEOpenOrQuitApp, 0L, false) != noErr)
  1150.             DisplayString ("\pAEInstallEventHandler failed (Open Application)\r");
  1151.         if (AEInstallEventHandler (kCoreEventClass, kAEQuitApplication,
  1152.                                         AEOpenOrQuitApp, 1L, false) != noErr)
  1153.             DisplayString ("\pAEInstallEventHandler failed (Quit Application)\r");
  1154.         if (AEInstallEventHandler (kCoreEventClass, kAEOpenDocuments,
  1155.                                         AEOpenOrPrintDoc, 0L, false) != noErr)
  1156.             DisplayString ("\pAEInstallEventHandler failed (Open Documents)\r");
  1157.         if (AEInstallEventHandler (kCoreEventClass, kAEPrintDocuments,
  1158.                                         AEOpenOrPrintDoc, 1L, false) != noErr)
  1159.             DisplayString ("\pAEInstallEventHandler failed (Print Documents)\r");
  1160.         if (AEInstallEventHandler (kCoreEventClass, kAEApplicationDied,
  1161.                                         AEAppDied, 0L, false) != noErr)
  1162.             DisplayString ("\pAEInstallEventHandler failed (Application died)\r");
  1163.     }
  1164.  
  1165.     /*
  1166.      * Install menus and menu handlers
  1167.      *
  1168.      * Enable File menu Launch item only if System 7 launching available
  1169.      * and can be done without terminating current application.
  1170.      */
  1171.  
  1172.     SkelApple ("\pAbout EventLog\311", DoAbout);
  1173.  
  1174.     fileMenu = GetMenu (fileMenuRes);
  1175.     (void) SkelMenu (fileMenu, DoFileMenu, nil, false, false);
  1176.  
  1177.      DisableItem (fileMenu, launchApp);
  1178.      if (SkelQuery (skelQHasGestalt) && Gestalt (gestaltOSAttr, &result) == noErr)
  1179.      {
  1180.          if ((result & (1L << gestaltLaunchFullFileSpec))
  1181.              && (result & (1L << gestaltLaunchCanReturn)))
  1182.              EnableItem (fileMenu, launchApp);
  1183.      }
  1184.  
  1185.     editMenu = GetMenu (editMenuRes);
  1186.     (void) SkelMenu (editMenu, nil, nil, false, false);
  1187.  
  1188.     logMenu = GetMenu (logMenuRes);
  1189.     (void) SkelMenu (logMenu, DoLogMenu, nil, false, true);
  1190.  
  1191.     SkelSetMenuHook (MyMenuHook);
  1192.  
  1193.     /*
  1194.      * Create windows and install handlers.
  1195.      */
  1196.  
  1197.     SetDWindowNotify (nil, Activate);
  1198.  
  1199.     helpWind = GetNewDWindow (helpWindRes, (WindowPtr) -1L);
  1200.     SetDWindowStyle (helpWind, 0, 0, 0, teJustLeft);
  1201.  
  1202.     h = GetResource ('TEXT', helpTextRes);    /* read help text */
  1203.     HLock (h);                        /* lock it and write to window */
  1204.     DisplayText (*h, GetHandleSize (h));
  1205.     HUnlock (h);
  1206.     ReleaseResource (h);            /* done with it, so goodbye */
  1207.     SetDWindowPos (helpWind, 0);    /* scroll back to top */
  1208.     /*ShowWindow (helpWind);*/
  1209.  
  1210.     logWind = GetNewDWindow (logWindRes, (WindowPtr) -1L);
  1211.  
  1212.     SkelSetEventHook (LogEvent);
  1213.     reportEvents = true;
  1214.     excludeLog = false;
  1215.  
  1216.     logFont = monaco;
  1217.     logSize = 9;
  1218.     logWrap = 0;
  1219.     logJust = teJustLeft;
  1220.     SetStyle ();
  1221.     ShowWindow (logWind);
  1222.  
  1223.     if (SkelQuery (skelQHasColorQD))
  1224.         selectWind = GetNewCWindow (selectWindRes, nil, (WindowPtr) -1L);
  1225.     else
  1226.         selectWind = GetNewWindow (selectWindRes, nil, (WindowPtr) -1L);
  1227.  
  1228.     (void) SkelWindow (selectWind,    /* the window */
  1229.                 Mouse,        /* mouse click handler */
  1230.                 nil,        /* key clicks are ignored */
  1231.                 Update,        /* window updating procedure */
  1232.                 Activate,    /* window activate/deactivate procedure */
  1233.                 nil,        /* hide window */
  1234.                 WClobber,    /* window disposal procedure */
  1235.                 nil,        /* idle proc */
  1236.                 false);        /* irrelevant */
  1237.  
  1238.     MakeControls (selectWind);
  1239.  
  1240.     /*
  1241.      * Process events until user quits, then clean up and exit.
  1242.      */
  1243.  
  1244. /*
  1245.     SetEventMask(everyEvent);
  1246.     SkelSetEventMask (SkelGetEventMask () | keyUpMask);
  1247. */
  1248.  
  1249.     SkelSetSuspendResume (DoSuspendResume);
  1250.  
  1251.     SkelEventLoop ();
  1252.  
  1253. /*
  1254.     SetEventMask(everyEvent - keyUpMask);
  1255. */
  1256.  
  1257.     SkelCleanup ();
  1258. }
  1259.